 /****************************************************************************
 * Copyright (C) 2010
 * by Dimok
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and
 * redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you
 * must not claim that you wrote the original software. If you use
 * this software in a product, an acknowledgment in the product
 * documentation would be appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and
 * must not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 * distribution.
 *
 * for WiiXplorer 2010
 ***************************************************************************/
#include <ogc/isfs.h>

#include "../Network/networkops.h"
#include "../Controls/Application.h"
#include "../FileOperations/Nand.hpp"
#include "../BootHomebrew/BootHomebrewTask.h"
#include "../SoundOperations/MusicPlayer.h"
#include "../SoundOperations/SoundHandler.hpp"
#include "../DeviceControls/DeviceHandler.hpp"
#include "../DeviceControls/DevicesSwap.h"
#include "../Prompts/ProgressWindow.h"
#include "../Prompts/PromptWindows.h"
#include "../Prompts/SearchWindow.h"
#include "../Tools/ErrorLog.h"
#include "../Themes/CTheme.h"
#include "../Menu/MainMenu.h"
#include "../stdafx.h"
#include "IosLoader.h"
#include "audio.h"
#include "video.h"
#include "input.h"
#include "sys.h"

extern "C" bool RebootApp()
{
	char filepath[MAXPATHLEN];
	
	if(strlen(Settings.UpdatePath) > 0 && Settings.UpdatePath[strlen(Settings.UpdatePath)-1] != '/')
		snprintf(filepath, sizeof(filepath), "%s/boot.dol", Settings.UpdatePath);
	else
		snprintf(filepath, sizeof(filepath), "%sboot.dol", Settings.UpdatePath);

	ClearArguments();
	AddBootArgument(filepath);
	
	BootHomebrewTask *task = new BootHomebrewTask(filepath);
	task->SetAutoRunOnLoadFinish(true);

	return true;
}

extern "C" void ExitApp()
{
	//! this should never happen, but its just in case here
	static bool bRunOnce = false;
	if(bRunOnce)
		return;
	bRunOnce = true;

	Settings.Save();
	
	ShutdownPads();
	
	Application::Instance()->quit();
	DevicesSwap::DestroyInstance();
	ErrorLog::DestroyInstance();
	MusicPlayer::DestroyInstance();
	SearchWindow::DestroyInstance();
	MainMenu::DestroyInstance();
	ProgressWindow::DestroyInstance();
	SoundHandler::DestroyInstance();
	Application::DestroyInstance();
	Resources::DestroyInstance();
	DeviceHandler::DestroyInstance();
	ThreadedTaskHandler::DestroyInstance();
	StopGX();
	gettextCleanUp();
	Theme::CleanUp();
	ShutdownAudio();
	DeInit_Network();
	Nand::Shutdown();
	USB_Deinitialize();
	
	if(Settings.BootIOS != Settings.EntraceIOS)
		IosLoader::ReloadIosKeepingRights(Settings.EntraceIOS);
}

extern "C" void __Sys_ResetCallback(void)
{
	Application::resetSystem();
}

extern "C" void __Sys_PowerCallback(void)
{
	Application::shutdownSystem();
}


extern "C" void Sys_Init(void)
{
	SYS_SetResetCallback(__Sys_ResetCallback);
	SYS_SetPowerCallback(__Sys_PowerCallback);
}

extern "C" void Sys_Reboot(void)
{
	ExitApp();
	STM_RebootSystem();
}

#define ShutdownToDefault	0
#define ShutdownToIdle		1
#define ShutdownToStandby	2

static void _Sys_Shutdown(int SHUTDOWN_MODE)
{
	ExitApp();

	if((CONF_GetShutdownMode() == CONF_SHUTDOWN_IDLE &&  SHUTDOWN_MODE != ShutdownToStandby) || SHUTDOWN_MODE == ShutdownToIdle) {
		s32 ret;

		ret = CONF_GetIdleLedMode();
		if(ret >= 0 && ret <= 2)
			STM_SetLedMode(ret);

		STM_ShutdownToIdle();
	} else {
		STM_ShutdownToStandby();
	}
}

extern "C" void Sys_Shutdown(void)
{
	_Sys_Shutdown(ShutdownToDefault);
}

extern "C" void Sys_ShutdownToIdle(void)
{
	_Sys_Shutdown(ShutdownToIdle);
}

extern "C" void Sys_ShutdownToStandby(void)
{
	_Sys_Shutdown(ShutdownToStandby);
}

extern "C" void Sys_LoadMenu(void)
{
	ExitApp();

	//! Priiloader shutup
	if(Settings.PriiloaderOverride)
	{
		*(u32 *)0x8132fffb = 0x50756e65;
		*(u32 *)0x817feff0 = 0x50756e65;	//! priiloader 0.8 beta 4+
		DCFlushRange((u32 *)0x8132fffb, 4);
		DCFlushRange((u32 *)0x817feff0, 4);
	}
	
	//! Return to the Wii system menu
	SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
}

extern "C" void Sys_BackToLoader(void)
{
	ExitApp();

	if (IsFromHBC())
		Sys_LoadHBC();

	//! Channel Version
	SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
}

extern "C" bool IsFromHBC()
{
	if(!(*((u32*) 0x80001800)))
		return false;

	char * signature = (char *) 0x80001804;
	if(strncmp(signature, "STUBHAXX", 8) == 0)
	{
		return true;
	}

	return false;
}

#define HBC_HAXX	0x0001000148415858LL
#define HBC_JODI	0x000100014A4F4449LL
#define HBC_1_0_7	0x00010001AF1BF516LL
#define HBC_LULZ	0x000100014C554C5ALL

#define HBF_NEW		0x0001000154484246LL
#define HBF_OLD		0x0001000148424630LL

extern "C" void Sys_LoadHBC(void)
{
	ExitApp();

	WII_Initialize();

	//! Try launching all known HBC/HBF titles in reversed released order 
	WII_LaunchTitle(HBF_NEW);
	WII_LaunchTitle(HBF_OLD);
	
	WII_LaunchTitle(HBC_LULZ);
	WII_LaunchTitle(HBC_1_0_7);
	WII_LaunchTitle(HBC_JODI);
	WII_LaunchTitle(HBC_HAXX);
	
	//! Back to system menu if all fails
	SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
}

void Sys_CheckSneek(void)  
{
	bool IsfsInit = !Nand::IsInitialized();
	if(IsfsInit)
		Nand::Startup();
	
	u32 ownerID;
	u16 groupID;
	u8  attributes, ownerperm, groupperm, otherperm;
	
	ISFS_GetAttr("/shared1/00000000.app", &ownerID, &groupID, &attributes, &ownerperm, &groupperm, &otherperm);
	
	if(IsfsInit)
		Nand::Shutdown();
	
	Settings.SneekRunning = false;
	if(otherperm)
		Settings.SneekRunning = true;
}

void Sys_CheckvWii(void)
{
	//! Check Device ID
	u32 deviceID = 0;
	ES_GetDeviceID(&deviceID);
	
	//! If it's greater than or equal to 0x20000000,
	//! then it's running on a Wii U.
	Settings.vWii = (deviceID >= 0x20000000);
}
